package com.cy.server;

import com.cy.container.Context;
import com.cy.container.Host;
import com.cy.container.Mapper;
import com.cy.container.Wrapper;
import com.cy.servlet.HttpServlet;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

/**
 * @Author ChenYan
 * @Date 2021/8/13 13:14
 * @Description
 */
public class Bootstrap {

    private Map<String, HttpServlet> servletMap = new HashMap<>();

    private Mapper mapper = new Mapper();

    private int port = 8080;

    public void setPort(int port) {
        this.port = port;
    }

    public int getPort() {
        return port;
    }

    /**
     * MiniCat启动第一步操作
     */
    public void start() throws IOException, DocumentException, ClassNotFoundException, InstantiationException, IllegalAccessException {
        //加载server.xml配置文件
        loadSever();

        System.out.println("----------->加载web.xml完成");

        int corePoolSize = 10;
        int maximumPoolSize = 100;
        long keepAliveTime = 100;
        TimeUnit unit = TimeUnit.SECONDS;
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(50);
        ThreadFactory threadFactory = Executors.defaultThreadFactory();
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);

        ServerSocket serverSocket = new ServerSocket(getPort());
        System.out.println("----------->MiniCat 启动在端口 :" + getPort());

        /**
         * 1.0版本
         * 浏览器请求后返回Hello MiniCat页面
         */
//        while (true){
//            Socket socket = serverSocket.accept();
//            OutputStream outputStream = socket.getOutputStream();
//            String content = "Hello MiniCat";
//            String httpHeader = HttpProtocolUtil.getHttpHeader200(content.getBytes().length);
//            outputStream.write((httpHeader + content).getBytes());
//        }

        /**
         * 2.0
         * 封装Request和Response对象，返回html静态资源文件
         */
//        while (true){
//            Socket socket = serverSocket.accept();
//
//            //封装Request和Response
//            Request request = new Request(socket.getInputStream());
//            Response response = new Response(socket.getOutputStream());
//
//            response.outputHtml(request.getUrl());
//            socket.close();
//        }

        /**
         * 3.0
         * 可以请求动态资源servlet
         */
//        while (true){
//            Socket socket = serverSocket.accept();
//
//            //封装Request和Response
//            Request request = new Request(socket.getInputStream());
//            Response response = new Response(socket.getOutputStream());
//
//            //没有servlet表示是静态资源
//            if (servletMap.get(request.getUrl()) == null){
//                response.outputHtml(request.getUrl());
//            }
//            else {
//                //动态资源请求
//                HttpServlet httpServlet = servletMap.get(request.getUrl());
//                httpServlet.service(request, response);
//            }
//
//            socket.close();
//        }

        /**
         * 4.0
         * 使用线程池
         */
        while (true){
            Socket socket = serverSocket.accept();
            RequestProcessor requestProcessor = new RequestProcessor(socket, mapper);
            threadPoolExecutor.execute(requestProcessor);
        }

    }

    /**
     * 加载服务
     */
    private void loadSever() throws DocumentException, ClassNotFoundException, InstantiationException, IllegalAccessException, FileNotFoundException {
        InputStream inputStream = Bootstrap.class.getClassLoader().getResourceAsStream("server.xml");
        SAXReader saxReader = new SAXReader();

        Document document = saxReader.read(inputStream);
        Element rootElement = document.getRootElement();

        Element connector = (Element) rootElement.selectSingleNode("//Connector");
        String port = connector.attributeValue("port");
        setPort(Integer.valueOf(port));
        //Connector
        List<Element> engines = connector.selectNodes("//Engine");
        //Engine
        for (Element engine : engines) {
            //Host
            List<Element> hosts = engine.selectNodes("//Host");
            for (Element host : hosts) {
                String hostName = host.attributeValue("name");
                String hostPath = host.attributeValue("appBase");

                hostName = hostName + ":" + port;
                loadApp(hostName, hostPath);
            }
        }

    }

    /**
     * 根据配置路径，查询所有的项目
     * @param hostName
     * @param hostPath
     */
    private void loadApp(String hostName, String hostPath) throws DocumentException, ClassNotFoundException, InstantiationException, IllegalAccessException, FileNotFoundException {
        Host host = new Host(hostName, hostPath);
        mapper.addHost(hostName, host);
        File rootFile = new File(hostPath);
        for (File file : rootFile.listFiles()) {
            if (file.isDirectory()){
                String contextName = file.getName();

                //加载解析配置文件
                loadServlet(host, contextName, file.getAbsolutePath());
            }
        }
    }

    /**
     * 加载web.xml
     */
    private void loadServlet(Host host, String contextName, String path) throws DocumentException, ClassNotFoundException, InstantiationException, IllegalAccessException, FileNotFoundException {
        Context context = new Context(contextName);

        File webFile = new File(path+"//web.xml");

        InputStream inputStream = new FileInputStream(webFile);
        SAXReader saxReader = new SAXReader();

        Document document = saxReader.read(inputStream);
        Element rootElement = document.getRootElement();

        List<Element> servletList = rootElement.selectNodes("//servlet");
        for (Element element : servletList) {
            //<servlet-name>com.cy</servlet-name>
            Element servletNameElement = (Element) element.selectSingleNode("servlet-name");
            String servletName = servletNameElement.getStringValue();
            //<servlet-class>com.cy.test.CyServlet</servlet-class>
            Element servletClassElement = (Element) element.selectSingleNode("servlet-class");
            String servletClass = servletClassElement.getStringValue();

            //找到对应的servletMapping
            //<url-pattern>/</url-pattern>
            Element servletMapping = (Element) rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletName + "']");
            String urlPattern = servletMapping.selectSingleNode("url-pattern").getStringValue();

            Wrapper wrapper = new Wrapper();
            wrapper.setServletClass(servletClass);

            String packagePath = servletClass.replaceAll("\\.","/");
            String classPath = "file:///"+path+"/"+packagePath+".class";
            classPath = classPath.replaceAll("\\\\","/");
            wrapper.setPath(classPath);

            //添加到mapper中
            mapper.addWrapper(host.getName(), host, contextName, context, urlPattern, wrapper);

//            servletMap.put(urlPattern, (HttpServlet) Class.forName(servletClass).newInstance());
        }

    }

    public static void main(String[] args) {
        System.out.println("开始启动MiniCat");
        Bootstrap bootstrap = new Bootstrap();
        try {
            bootstrap.start();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

}
